﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SangoBang;
using System.Xml;

namespace TestProject1
{
    /// <summary>
    /// Summary description for UserAction
    /// </summary>
    [TestClass]
    public class UserAction
    {
        public UserAction()
        {
            mEventController = new EventController();

            string msg;
            for (int i = 0; i < mPlayerNum; ++i)
            {
                msg = "<message type=\"newuser\"><user>" + mUsernames[i] + "</user></message>";
                string guid = mEventController.OnReceiveMsg(msg, "");
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(guid);
                XmlElement replyMsgElement = doc.DocumentElement;
                mGuids[i] = replyMsgElement.FirstChild.InnerText;
            }
        }
        private string[] mUsernames = { "player1", "player2", "player3", "player4", "player5", "player6", "player7", "player8", "player9" };
        private string[] mGuids = new string[9];
        private string[] mRoles = new string[9];
        private EventController mEventController;
        private TestContext testContextInstance;
        private int mPlayerNum = 4;
        int[] mPlayerHP = { 0, 0, 0, 0 };
       
        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        /// <summary>
        /// test kill suffer cure
        /// </summary>
        public void UserAction1()
        {
            List<MessageListener> listeners = new List<MessageListener> ();
            string msg;
            XmlDocument doc = new XmlDocument();
            
            int i = 0;
            //add 4 Listener to the List
            for (i = 0; i < 4; i++) {
                listeners.Add(new MessageListener());
                listeners[i].StartListen(mGuids[i], mEventController, mUsernames[i]);
            }
            //player1 start game;
            mEventController.OnReceiveMsg("<message type=\"startGame\"></message>", mGuids[0]);

            msg = listeners[0].ExpectMessage("characterCard");
            Assert.AreNotEqual(null, msg);
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(msg);
            XmlElement xroot = xml.DocumentElement;
            Console.WriteLine();
            for (i = 0; i < 4; i++)
            {
                XmlElement child = (XmlElement)xroot.ChildNodes[i];
                mPlayerHP[i] = Int32.Parse(child.GetAttribute("hp"));
                Console.WriteLine("     Player{0} HP is {1}", i+1, mPlayerHP[i]);
            }
            Console.WriteLine();


            //wait for dispatch card finish
            for (i = 0; i < 4; i++) {
                msg = listeners[i].ExpectMessage("dispatchCardFinish");
                Assert.AreNotEqual(null, msg);
            }
            // player1 kill player2
            msg = "<message type=\"playerAction\"><action type=\"kill\" target=\"player2\"></action></message>";
            mEventController.OnReceiveMsg(msg, mGuids[0]);
            for (i = 0; i < 4; i++)
            {
                msg = listeners[i].ExpectMessage("playerAction");
                Assert.AreNotEqual(null, msg);
                //msg = "<message type=\"playerAction\"><action type=\"kill\" player=\"player1\" target=\"player2\"></action></message>";
                doc.LoadXml(msg);
                XmlElement msgElement = doc.DocumentElement;
                Assert.AreEqual("playerAction",msgElement.GetAttribute("type"));
                XmlElement actionElement = (XmlElement)msgElement.GetElementsByTagName("action")[0];
                Assert.AreEqual("kill", actionElement.GetAttribute("type"));
                Assert.AreEqual("player1", actionElement.GetAttribute("player"));
                Assert.AreEqual("player2", actionElement.GetAttribute("target"));
            }
            //player2 suffer
            msg = "<message type=\"playerAction\"><action type=\"suffer\"></action></message>";
            mPlayerHP[1]--;
            Console.WriteLine();
            Console.WriteLine("     Player2 HP minus 1\n");
            Console.WriteLine();
            mEventController.OnReceiveMsg(msg, mGuids[1]);
            for (i = 0; i < 4; i++) {
             
                msg = listeners[i].ExpectMessage("playerAction");
                Assert.AreNotEqual(null, msg);
           //     msg = "<message type=\"playerAction\"><action type=\"suffer\" player=\"player2\"></action></message>";
                doc.LoadXml(msg);
                XmlElement msgElement = doc.DocumentElement;
                Assert.AreEqual("playerAction", msgElement.GetAttribute("type"));
                XmlElement actionElemnt = (XmlElement)msgElement.GetElementsByTagName("action")[0];
                Assert.AreEqual("suffer", actionElemnt.GetAttribute("type"));
                Assert.AreEqual("player2", actionElemnt.GetAttribute("player"));
            }
            //player status update
            foreach (var listener in listeners) 
            {
                msg = listener.ExpectMessage("playerUpdate");
                Assert.AreNotEqual(null, msg);

                //msg = "<message type=\"playerUpdate\"><playerStatus player=\"player1\" cardNumber=\"3\" life=\"4\"></playerStatus>" + 
                //    "<playerStatus player=\"player2\" cardNumber=\"4\" life=\"3\"></playerStatus>"+"</message>";
                doc.LoadXml(msg);
                XmlElement msgElement = doc.DocumentElement;
                Assert.AreEqual("playerUpdate", msgElement.GetAttribute("type"));
                var statusElements = msgElement.GetElementsByTagName("playerStatus");
                foreach (XmlElement element in statusElements) 
                {
                    string name = element.GetAttribute("player");
                    if (name == "player1") 
                    {
                        Assert.AreEqual("3", element.GetAttribute("cardNumber"));
                        Assert.AreEqual("4", element.GetAttribute("life"));
                    }
                    if (name == "player2")
                    {
                        Assert.AreEqual("4", element.GetAttribute("cardNumber"));
                        Assert.AreEqual(mPlayerHP[1].ToString(), element.GetAttribute("life"));
                    }
                }
            }
            //player2 cure
            msg = "<message type=\"playerAction\"><action type=\"cure\" target=\"player2\"></action></message>";
            mPlayerHP[1]++;
            Console.WriteLine();
            Console.WriteLine("     Player2 HP plus 1\n");
            Console.WriteLine();
            mEventController.OnReceiveMsg(msg, mGuids[1]);
            for (i = 0; i < 4; i++)
            {               
                msg = listeners[i].ExpectMessage("playerAction");
                Assert.AreNotEqual(null, msg);
                //msg = "<message type=\"playerAction\"><action type=\"cure\" player=\"player2\" target=\"player2\"></action></message>";
                doc.LoadXml(msg);
                XmlElement msgElement = doc.DocumentElement;
                Assert.AreEqual("playerAction", msgElement.GetAttribute("type"));
                XmlElement actionElement = (XmlElement)msgElement.GetElementsByTagName("action")[0];
                Assert.AreEqual("cure", actionElement.GetAttribute("type"));
                Assert.AreEqual("player2", actionElement.GetAttribute("player"));
                Assert.AreEqual("player2", actionElement.GetAttribute("target"));
            }
            //player status update
            foreach (var listener in listeners)
            {
                msg = listener.ExpectMessage("playerUpdate");
                Assert.AreNotEqual(null, msg);

                //msg = "<message type=\"playerUpdate\"><playerStatus player=\"player1\" cardNumber=\"3\" life=\"4\"></playerStatus>" + 
                //    "<playerStatus player=\"player2\" cardNumber=\"3\" life=\"4\"></playerStatus>"+"</message>";
                doc.LoadXml(msg);
                XmlElement msgElement = doc.DocumentElement;
                Assert.AreEqual("playerUpdate", msgElement.GetAttribute("type"));
                var statusElements = msgElement.GetElementsByTagName("playerStatus");
                foreach (XmlElement element in statusElements)
                {
                    string name = element.GetAttribute("player");
                    if (name == "player1")
                    {
                        Assert.AreEqual("3", element.GetAttribute("cardNumber"));
                        Assert.AreEqual("4", element.GetAttribute("life"));
                    }
                    if (name == "player2")
                    {
                        Assert.AreEqual("3", element.GetAttribute("cardNumber"));
                        Assert.AreEqual(mPlayerHP[1].ToString(), element.GetAttribute("life"));
                    }
                }
            }
        }
        [TestMethod]
        ///<summary>
        ///test kill miss
        ///</summary>
        public void UserAction2() 
        {
            List<MessageListener> listeners = new List<MessageListener>();
            string msg;
            XmlDocument doc = new XmlDocument();

            int i = 0;
            for (i = 0; i < 4; i++)
            {
                listeners.Add(new MessageListener());
                listeners[i].StartListen(mGuids[i], mEventController,mUsernames[i]);
            }
            //player1 start game;
            mEventController.OnReceiveMsg("<message type=\"startGame\"></message>", mGuids[0]);


            msg = listeners[0].ExpectMessage("characterCard");
            Assert.AreNotEqual(null, msg);
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(msg);
            XmlElement xroot = xml.DocumentElement;
            Console.WriteLine();
            for (i = 0; i < 4; i++)
            {
                XmlElement child = (XmlElement)xroot.ChildNodes[i];
                mPlayerHP[i] = Int32.Parse(child.GetAttribute("hp"));
                Console.WriteLine("     Player{0} HP is {1}", i + 1, mPlayerHP[i]);
            }
            Console.WriteLine();

            //wait for dispatch card finish
            for (i = 0; i < 4; i++)
            {
                msg = listeners[i].ExpectMessage("dispatchCardFinish");
                Assert.AreNotEqual(null, msg);
            }

            // player1 kill player2
            msg = "<message type=\"playerAction\"><action type=\"kill\" target=\"player2\"></action></message>";
            mEventController.OnReceiveMsg(msg, mGuids[0]);
            for (i = 0; i < 4; i++)
            {
                msg = listeners[i].ExpectMessage("playerAction");
                Assert.AreNotEqual(null, msg);
                
            }
            //player2 miss
            msg = "<message type=\"playerAction\"><action type=\"miss\"></action></message>";
            mEventController.OnReceiveMsg(msg, mGuids[1]);
            for (i = 0; i < 4; i++)
            {
                msg = listeners[i].ExpectMessage("playerAction");
                Assert.AreNotEqual(null, msg);
                //     msg = "<message type=\"playerAction\"><action type=\"suffer\" player=\"player2\"></action></message>";
                doc.LoadXml(msg);
                XmlElement msgElement = doc.DocumentElement;
                Assert.AreEqual("playerAction", msgElement.GetAttribute("type"));
                XmlElement actionElemnt = (XmlElement)msgElement.GetElementsByTagName("action")[0];
                Assert.AreEqual("miss", actionElemnt.GetAttribute("type"));
                Assert.AreEqual("player2", actionElemnt.GetAttribute("player"));
            }
            //player status update
            foreach (var listener in listeners)
            {
                msg = listener.ExpectMessage("playerUpdate");
                Assert.AreNotEqual(null, msg);

                //msg = "<message type=\"playerUpdate\"><playerStatus player=\"player1\" cardNumber=\"3\" life=\"4\"></playerStatus>" + 
                //    "<playerStatus player=\"player2\" cardNumber=\"4\" life=\"3\"></playerStatus>"+"</message>";
                doc.LoadXml(msg);
                XmlElement msgElement = doc.DocumentElement;
                Assert.AreEqual("playerUpdate", msgElement.GetAttribute("type"));
                var statusElements = msgElement.GetElementsByTagName("playerStatus");
                foreach (XmlElement element in statusElements)
                {
                    string name = element.GetAttribute("player");
                    if (name == "player1")
                    {
                        Assert.AreEqual("3", element.GetAttribute("cardNumber"));
                        Assert.AreEqual(mPlayerHP[0].ToString(), element.GetAttribute("life"));
                    }
                    if (name == "player2")
                    {
                        Assert.AreEqual("3", element.GetAttribute("cardNumber"));
                        Assert.AreEqual(mPlayerHP[1].ToString(), element.GetAttribute("life")); //////////Problem is Here!!!
                    }
                }
            }            
        }
        [TestMethod]
        ///<summary>
        ///test user action in sequence, include action end action start, 
        /// and dispatch card when action starts 
        ///</smmary>
        public void UserAction3()
        {
            List<MessageListener> listeners = new List<MessageListener>();
            string msg;
            XmlDocument doc = new XmlDocument();

            int i = 0;
            for (i = 0; i < 4; i++)
            {
                listeners.Add(new MessageListener());
                listeners[i].StartListen(mGuids[i], mEventController,mUsernames[i]);
            }
            //player1 start game;
            mEventController.OnReceiveMsg("<message type=\"startGame\"></message>", mGuids[0]);
            for (i = 0; i < 4; i++)
            {
                msg = listeners[i].ExpectMessage("dispatchCardFinish");
                Assert.AreNotEqual(null, msg);
            }

            for (int j = 2; j > 0; --j)
            {
                //player1's action
                for (i = 0; i < 4; i++)
                {
                    msg = listeners[i].ExpectMessage("playerActionStart");
                    //msg = "<message type=\"playerActionStart\" player=\"player1\"/>";
                    Assert.AreNotEqual(null, msg);
                    doc.LoadXml(msg);
                    XmlElement msgElement = doc.DocumentElement;
                    Assert.AreEqual("player1", msgElement.GetAttribute("player"));
                }

                msg = listeners[0].ExpectMessage("gameCard", "playerUpdate");
                Assert.AreNotEqual(null, msg);
                //other player should not get cards.
                msg = listeners[1].ExpectMessage("gameCard", "playerUpdate");
                Assert.AreEqual(null, msg);
                msg = listeners[2].ExpectMessage("gameCard", "playerUpdate");
                Assert.AreEqual(null, msg);
                msg = listeners[3].ExpectMessage("gameCard", "playerUpdate");
                Assert.AreEqual(null, msg);
                
                foreach (var listener in listeners)
                {
                    msg = listener.ExpectMessage("playerUpdate");
                    Assert.AreNotEqual(null, msg);
                }
                mEventController.OnReceiveMsg("<message type=\"playerActionFinish\"></message>", mGuids[0]);

                //player2's action
                for (i = 0; i < 4; i++)
                {
                    msg = listeners[i].ExpectMessage("playerActionStart");
                    //msg = "<message type=\"playerActionStart\" player=\"player2\"/>";
                    Assert.AreNotEqual(null, msg);
                    doc.LoadXml(msg);
                    XmlElement msgElement = doc.DocumentElement;
                    Assert.AreEqual("player2", msgElement.GetAttribute("player"));
                }

                msg = listeners[1].ExpectMessage("gameCard");
                Assert.AreNotEqual(null, msg);
                mEventController.OnReceiveMsg("<message type=\"playerActionFinish\"></message>", mGuids[1]);

                //player3's action
                for (i = 0; i < 4; i++)
                {
                    msg = listeners[i].ExpectMessage("playerActionStart");
                    //msg = "<message type=\"playerActionStart\" player=\"player3\"/>";
                    Assert.AreNotEqual(null, msg);
                    doc.LoadXml(msg);
                    XmlElement msgElement = doc.DocumentElement;
                    Assert.AreEqual("player3", msgElement.GetAttribute("player"));
                }

                msg = listeners[2].ExpectMessage("gameCard");
                Assert.AreNotEqual(null, msg);
                mEventController.OnReceiveMsg("<message type=\"playerActionFinish\"></message>", mGuids[2]);

                //player4's action
                for (i = 0; i < 4; i++)
                {
                    msg = listeners[i].ExpectMessage("playerActionStart");
                    //msg = "<message type=\"playerActionStart\" player=\"player4\"/>";
                    Assert.AreNotEqual(null, msg);
                    doc.LoadXml(msg);
                    XmlElement msgElement = doc.DocumentElement;
                    Assert.AreEqual("player4", msgElement.GetAttribute("player"));
                }

                msg = listeners[3].ExpectMessage("gameCard");
                Assert.AreNotEqual(null, msg);
                mEventController.OnReceiveMsg("<message type=\"playerActionFinish\"></message>", 
                    mGuids[3]);
            }
        }
        ///<summary>
        ///test for discard, and check for cards number
        [TestMethod]
        public void Discard() 
        {
            List<MessageListener> listeners = new List<MessageListener>();
            string msg;
            XmlDocument doc = new XmlDocument();
            XmlElement msgElement;
            int i = 0;
            for (i = 0; i < 4; i++)
            {
                listeners.Add(new MessageListener());
                listeners[i].StartListen(mGuids[i], mEventController, mUsernames[i]);
            }
            //player1 start game;
            mEventController.OnReceiveMsg("<message type=\"startGame\"></message>", mGuids[0]);

            msg = listeners[0].ExpectMessage("characterCard");
            Assert.AreNotEqual(null, msg);
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(msg);
            XmlElement xroot = xml.DocumentElement;
            Console.WriteLine();
            for (i = 0; i < 4; i++)
            {
                XmlElement child = (XmlElement)xroot.ChildNodes[i];
                mPlayerHP[i] = Int32.Parse(child.GetAttribute("hp"));
                Console.WriteLine("     Player{0} HP is {1}", i + 1, mPlayerHP[i]);
            }
            Console.WriteLine();

            // 所有人收到游戏牌,数量等于4
            for ( i = 0; i < mPlayerNum; ++i)
            {                
                msg = listeners[i].ExpectMessage("gameCard");
                doc.LoadXml(msg);
                msgElement = doc.DocumentElement;
                Assert.AreEqual(4, msgElement.GetElementsByTagName("gameCard").Count, "should get 4 game card");
                foreach (XmlElement gameCard in msgElement)
                {
                    Assert.AreEqual("gameCard", gameCard.Name, "should only contain gameCard element");
                }
            }
            for (i = 0; i < 4; i++)
            {
                msg = listeners[i].ExpectMessage("dispatchCardFinish");
                Assert.AreNotEqual(null, msg);
            }

            //player1's action
            for (i = 0; i < 4; i++)
            {
                msg = listeners[i].ExpectMessage("playerActionStart");
                //msg = "<message type=\"playerActionStart\" player=\"player1\"/>";
                Assert.AreNotEqual(null, msg);
                doc.LoadXml(msg);
                msgElement = doc.DocumentElement;
                Assert.AreEqual("player1", msgElement.GetAttribute("player"));
            }
            msg = listeners[0].ExpectMessage("gameCard");
            Assert.AreNotEqual(null, msg);
            doc.LoadXml(msg);
            msgElement = doc.DocumentElement;
            Assert.AreEqual(2, msgElement.GetElementsByTagName("gameCard").Count, "should get 2 game cards");
            foreach (var listener in listeners)
            {
                msg = listener.ExpectMessage("playerUpdate");
                Assert.AreNotEqual(null, msg);
                doc.LoadXml(msg);
                msgElement = doc.DocumentElement;                
                var statusElements = msgElement.GetElementsByTagName("playerStatus");
                foreach (XmlElement element in statusElements)
                {
                    string name = element.GetAttribute("player");
                    Assert.AreEqual(name, "player1");
                    Assert.AreEqual("6", element.GetAttribute("cardNumber"));
                    Assert.AreEqual(mPlayerHP[0].ToString(), element.GetAttribute("life"));                                     
                }
            }
            //player1 discard
                mEventController.OnReceiveMsg("<message type=\"discard\">"+
                        "<gameCard>kill</gameCard>" +
                        "<gameCard>miss</gameCard>" + "</message>", 
                        mGuids[0]);
            foreach (var listener in listeners)
            {
                msg = listener.ExpectMessage("playerUpdate");
                Assert.AreNotEqual(null, msg);       
                doc.LoadXml(msg);
                msgElement = doc.DocumentElement;
                var statusElements = msgElement.GetElementsByTagName("playerStatus");
                foreach (XmlElement element in statusElements)
                {
                    string name = element.GetAttribute("player");
                    Assert.AreEqual(name, "player1");
                    Assert.AreEqual("4", element.GetAttribute("cardNumber"));
                    Assert.AreEqual(mPlayerHP[0].ToString(), element.GetAttribute("life"));
                }
             
            }
        }
    }
}
